home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume6 / rpc2 / part02 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  52.1 KB

  1. Subject:  v06i090:  Sun RPC Source (rpc2), Part02/11
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: sun!ferne!marks (Mark Stein)
  6. Mod.sources: Volume 6, Issue 90
  7. Archive-name: rpc2/Part02
  8.  
  9. [  All I have done is verify that the shar files unpack correctly.  -r$ ]
  10.  
  11. Sun RPC source (part 2 of 11).  This software package contains code
  12. and documentation for Revision 3.0 of the Sun Remote Procedure Call
  13. library.  In addition, a beta version of the XDR/RPC protocol compiler
  14. is included.  Comments about this latest release may be mailed to
  15. sun!rpc or rpc@sun.com.
  16.  
  17. Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  18. unrestricted use provided that this legend is included on all tape
  19. media and as a part of the software program in whole or part.  Users
  20. may copy or modify Sun RPC without charge, but are not authorized to
  21. license or distribute it to anyone else except as part of a product or
  22. program developed by the user.
  23.  
  24. - - - - - - - - - C U T - H E R E - - - - - - - - - - - - - - - - - -
  25. #! /bin/sh
  26. # This is a shell archive, meaning:
  27. # 1. Remove everything above the #! /bin/sh line.
  28. # 2. Save the resulting text in a file.
  29. # 3. Execute the file with /bin/sh (not csh) to create:
  30. #    rpc/doc/rpc.prog.p1
  31. # This archive created: Mon Jul 14 16:54:58 1986
  32. export PATH; PATH=/bin:/usr/bin:$PATH
  33. for d in rpc rpc/doc rpc/rpclib rpc/tools rpc/toys rpc/rpclib/profiled rpc/rpcgen rpc/rpcgen/test
  34. do
  35.     if test ! -d $d
  36.     then
  37.         echo "shar: Making directory $d"
  38.         mkdir $d
  39.         chmod 755 $d
  40.     fi
  41. done
  42. echo shar: "extracting 'rpc/doc/rpc.prog.p1'" '(49365 characters)'
  43. if test -f 'rpc/doc/rpc.prog.p1'
  44. then
  45.     echo shar: "will not over-write existing file 'rpc/doc/rpc.prog.p1'"
  46. else
  47. sed 's/^X//' << \SHAR_EOF > 'rpc/doc/rpc.prog.p1'
  48. X.PL RIGHT
  49. X.TL
  50. XRemote Procedure Call
  51. X.br
  52. XProgramming Guide
  53. X.bp
  54. X.NH
  55. XIntroduction
  56. X.LP
  57. XThis document is intended for programmers
  58. Xwho wish to write network applications
  59. Xusing remote procedure calls (explained below),
  60. Xthus avoiding low-level system primitives based on sockets.
  61. XThe reader must be familiar with the C programming language,
  62. Xand should have a working knowledge of network theory.
  63. X.LP
  64. XPrograms that communicate over a network
  65. Xneed a paradigm for communication.
  66. XA low-level mechanism might
  67. Xsend a signal on the arrival of incoming packets,
  68. Xcausing a network signal handler to execute.
  69. XA high-level mechanism would be the Ada
  70. X.LW rendezvous .
  71. XThe method used at Sun is the
  72. XRemote Procedure Call (RPC) paradigm,
  73. Xin which a client communicates with a server.
  74. XIn this process,
  75. Xthe client first calls a procedure to send a data packet to the server.
  76. XWhen the packet arrives, the server calls a dispatch routine,
  77. Xperforms whatever service is requested, sends back the reply,
  78. Xand the procedure call returns to the client.
  79. X.NH 2
  80. XLayers of RPC
  81. X.LP
  82. XThe RPC interface is divided into three layers.
  83. XThe highest layer is totally transparent to the programmer.
  84. XTo illustrate,
  85. Xat this level a program can contain a call to
  86. X.LW rnusers() ,
  87. Xwhich returns the number of users on a remote machine.
  88. XYou don't have to be aware that RPC is being used,
  89. Xsince you simply make the call in a program,
  90. Xjust as you would call
  91. X.LW malloc() .
  92. X.LP
  93. XAt the middle layer, the routines
  94. X.LW registerrpc()
  95. Xand
  96. X.LW callrpc()
  97. Xare used to make RPC calls:
  98. X.LW registerrpc()
  99. Xobtains a unique system-wide number, while
  100. X.LW callrpc()
  101. Xexecutes a remote procedure call.
  102. XThe
  103. X.LW rnusers()
  104. Xcall is implemented using these two routines.
  105. XThe middle-layer routines are designed for most common applications,
  106. Xand shield the user from knowing about sockets.
  107. X.LP
  108. XThe lowest layer is for more sophisticated applications,
  109. Xsuch as altering the defaults of the routines.
  110. XAt this layer, you can explicitly manipulate
  111. Xsockets that transmit RPC messages.
  112. XThis level should be avoided if possible.
  113. X.LP
  114. XSection 2 of this manual illustrates use of the highest two layers
  115. Xwhile Section 3 presents the low-level interface.
  116. XSection 4 of the manual discusses miscellaneous topics.
  117. XThe final section summarizes
  118. Xall the entry points into the RPC system.
  119. X.LP
  120. XAlthough this document only discusses the interface to C,
  121. Xremote procedure calls can be made from any language.
  122. XEven though this document discusses RPC
  123. Xwhen it is used to communicate
  124. Xbetween processes on different machines,
  125. Xit works just as well for communication
  126. Xbetween different processes on the same machine.
  127. X.NH 2
  128. XThe RPC Paradigm
  129. X.LP
  130. XHere is a diagram of the RPC paradigm:
  131. X.LP
  132. X.PL FULL
  133. X.PS
  134. XL1: arrow down 1i "client " rjust "program " rjust
  135. XL2: line right 1.5i "\fLcallrpc()\fP" "function"
  136. Xmove up 1.5i; line dotted down 6i; move up 4.5i
  137. Xarrow right 1i
  138. XL3: arrow down 1i "execute " rjust "request " rjust
  139. XL4: arrow right 1.5i "call" "service"
  140. XL5: arrow down 1i " service" ljust " executes" ljust
  141. XL6: arrow left 1.5i "\fLreturn\fP" "answer"
  142. XL7: arrow down 1i "request " rjust "completed " rjust
  143. XL8: line left 1i
  144. Xarrow left 1.5i "\fLreturn\fP" "reply"
  145. XL9: arrow down 1i "program " rjust "continues " rjust
  146. Xline dashed down from L2 to L9
  147. Xline dashed down from L4 to L7
  148. Xline dashed up 1i from L3 "service " rjust "daemon " rjust
  149. Xarrow dashed down 1i from L8
  150. Xmove right 1i from L3
  151. Xbox invis "Machine B"
  152. Xmove left 1.2i from L2; move down
  153. Xbox invis "Machine A"
  154. X.PE
  155. X.FN "Network Communication with the Remote Procedure Call"
  156. X.PL RIGHT
  157. X.bp
  158. X.NH
  159. XHigher Layers of RPC
  160. X.NH 2
  161. XHighest Layer
  162. X.LP
  163. XImagine you're writing a program that needs to know
  164. Xhow many users are logged into a remote machine.
  165. XYou can do this by calling the library routine
  166. X.LW rnusers() ,
  167. Xas illustrated below:
  168. X.BS
  169. X.LS
  170. X#include <stdio.h>
  171. X.sp.5
  172. Xmain(argc, argv)
  173. X    int argc;
  174. X    char **argv;
  175. X{
  176. X    unsigned num;
  177. X.sp.5
  178. X    if (argc < 2) {
  179. X        fprintf(stderr, "usage: rnusers hostname\en");
  180. X        exit(1);
  181. X    }
  182. X    if ((num = rnusers(argv[1])) < 0) {
  183. X        fprintf(stderr, "error: rnusers\en");
  184. X        exit(-1);
  185. X    }
  186. X    printf("%d users on %s\en", num, argv[1]);
  187. X    exit(0);
  188. X}
  189. X.Lf
  190. X.BE
  191. XRPC library routines such as
  192. X.LW rnusers()
  193. Xare in the RPC services library
  194. X.LW librpcsvc.a .
  195. XThus, the program above should be compiled with
  196. X.BS
  197. X.LS
  198. X% cc \fIprogram\fP.c -lrpcsvc
  199. X.Lf
  200. X.BE
  201. XThis routine, and other RPC library routines,
  202. Xare documented in section 3R of the
  203. X.I "System Interface Manual for the Sun Workstation" .
  204. XHere is a table of RPC service library routines
  205. Xavailable to the C programmer:
  206. X.TN "RPC Service Library Routines"
  207. X.TS
  208. Xbox;
  209. XcfBI s
  210. Xc c
  211. XlfL l.
  212. X.sp.5
  213. X\s+2RPC Service Library Routines\s-2
  214. X.sp.5
  215. X_
  216. X\fIroutine    description\fP
  217. X_
  218. Xrnusers()    return number of users on remote machine
  219. Xrusers()    return information about users on remote machine
  220. Xhavedisk()    determine if remote machine has disk
  221. Xrstat()     get performance data from remote kernel
  222. Xrwall()     write to specified remote machines
  223. Xgetmaster()    get name of YP master
  224. Xgetrpcport()    get RPC port number
  225. Xyppasswd()    update user password in yellow pages
  226. X.TE
  227. X.LP
  228. XThe other RPC services \(em
  229. X.LW ether ,
  230. X.LW mount ,
  231. X.LW rquota ,
  232. Xand
  233. X.LW spray
  234. X\(em are not available to the C programmer as library routines.
  235. XThey do, however,
  236. Xhave RPC program numbers so they can be invoked with
  237. X.LW callrpc() ,
  238. Xwhich will be discussed in the next section.
  239. X.bp
  240. X.NH 2
  241. XIntermediate Layer
  242. X.LP
  243. XThe simplest interface, which explicitly makes RPC
  244. Xcalls, uses the functions
  245. X.LW callrpc()
  246. Xand
  247. X.LW registerrpc() .
  248. XUsing this method, another way to get the number of remote users is:
  249. X.BS
  250. X.LS
  251. X#include <stdio.h>
  252. X#include <rpcsvc/rusers.h>
  253. X.sp.5
  254. Xmain(argc, argv)
  255. X    int argc;
  256. X    char **argv;
  257. X{
  258. X    unsigned long nusers;
  259. X.sp.5
  260. X    if (argc < 2) {
  261. X        fprintf(stderr, "usage: nusers hostname\en");
  262. X        exit(-1);
  263. X    }
  264. X    if (callrpc(argv[1],
  265. X      RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
  266. X      xdr_void, 0, xdr_u_long, &nusers) != 0) {
  267. X        fprintf(stderr, "error: callrpc\en");
  268. X        exit(1);
  269. X    }
  270. X    printf("%d users on %s\en", nusers, argv[1]);
  271. X    exit(0);
  272. X}
  273. X.Lf
  274. X.BE
  275. XA program number, version number, and procedure number
  276. Xdefines each RPC procedure.
  277. XThe program number defines a group
  278. Xof related remote procedures, each of which has a different
  279. Xprocedure number.
  280. XEach program also has a version number,
  281. Xso when a minor change is made to a remote service
  282. X(adding a new procedure, for example),
  283. Xa new program number doesn't have to be assigned.
  284. XWhen you want to call a procedure to
  285. Xfind the number of remote users, you look up the appropriate
  286. Xprogram, version and procedure numbers
  287. Xin a manual, similar to when you look up the name of memory
  288. Xallocator when you want to allocate memory.
  289. X.LP
  290. XThe simplest routine in the RPC library
  291. Xused to make remote procedure calls is
  292. X.LW callrpc() .
  293. XIt has eight parameters.
  294. XThe first is the name of the remote machine.
  295. XThe next three parameters
  296. Xare the program, version, and procedure numbers.
  297. XThe following two parameters
  298. Xdefine the argument of the RPC call, and the final two parameters
  299. Xare for the return value of the call.
  300. XIf it completes successfully,
  301. X.LW callrpc()
  302. Xreturns zero, but nonzero otherwise.
  303. XThe exact meaning of the return codes is found in
  304. X.LW <rpc/clnt.h> ,
  305. Xand is in fact an
  306. X.LW "enum clnt_stat"
  307. Xcast into an integer.
  308. X.LP
  309. XSince data types may be represented differently on different machines,
  310. X.LW callrpc()
  311. Xneeds both the type of the RPC argument, as well as
  312. Xa pointer to the argument itself (and similarly for the result).  For
  313. X.LW RUSERSPROC_NUM ,
  314. Xthe return value is an
  315. X.LW "unsigned long" ,
  316. Xso
  317. X.LW callrpc()
  318. Xhas
  319. X.LW xdr_u_long
  320. Xas its first return parameter, which says
  321. Xthat the result is of type
  322. X.LW "unsigned long" ,
  323. Xand
  324. X.LW &nusers
  325. Xas its second return parameter,
  326. Xwhich is a pointer to where the long result will be placed.  Since
  327. X.LW RUSERSPROC_NUM
  328. Xtakes no argument, the argument parameter of
  329. X.LW callrpc()
  330. Xis
  331. X.LW xdr_void .
  332. X.LP
  333. XAfter trying several times to deliver a message, if
  334. X.LW callrpc()
  335. Xgets no answer, it returns with an error code.
  336. XThe delivery mechanism is UDP,
  337. Xwhich stands for User Datagram Protocol.
  338. XMethods for adjusting the number of retries
  339. Xor for using a different protocol require you to use the lower
  340. Xlayer of the RPC library, discussed later in this document.
  341. XThe remote server procedure
  342. Xcorresponding to the above might look like this:
  343. X.BS
  344. X.LS
  345. Xchar *
  346. Xnuser(indata)
  347. X    char *indata;
  348. X{
  349. X    static int nusers;
  350. X.sp.5
  351. X    /*
  352. X     * code here to compute the number of users
  353. X     * and place result in variable nusers
  354. X     */
  355. X    return((char *)&nusers);
  356. X}
  357. X.Lf
  358. X.BE
  359. X.LP
  360. XIt takes one argument, which is a pointer to the input
  361. Xof the remote procedure call (ignored in our example),
  362. Xand it returns a pointer to the result.
  363. XIn the current version of C,
  364. Xcharacter pointers are the generic pointers,
  365. Xso both the input argument and the return value are cast to
  366. X.LW "char *" .
  367. X.LP
  368. XNormally, a server registers all of the RPC calls it plans
  369. Xto handle, and then goes into an infinite loop waiting to service requests.
  370. XIn this example, there is only a single procedure
  371. Xto register, so the main body of the server would look like this:
  372. X.BS
  373. X.LS
  374. X#include <stdio.h>
  375. X#include <rpcsvc/rusers.h>
  376. X.sp.5
  377. Xchar *nuser();
  378. X.sp.5
  379. Xmain()
  380. X{
  381. X    registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
  382. X        nuser, xdr_void, xdr_u_long);
  383. X    svc_run();        /* never returns */
  384. X    fprintf(stderr, "Error: svc_run returned!\en");
  385. X    exit(1);
  386. X}
  387. X.Lf
  388. X.BE
  389. X.LP
  390. XThe
  391. X.LW registerrpc()
  392. Xroutine establishes what C procedure
  393. Xcorresponds to each RPC procedure number.
  394. XThe first three parameters,
  395. X.LW RUSERPROG ,
  396. X.LW RUSERSVERS ,
  397. Xand
  398. X.LW RUSERSPROC_NUM
  399. Xare the program, version, and procedure numbers
  400. Xof the remote procedure to be registered;
  401. X.LW nuser()
  402. Xis the name of the C procedure implementing it;
  403. Xand
  404. X.LW xdr_void
  405. Xand
  406. X.LW xdr_u_long
  407. Xare the types of the input to and output from the procedure.
  408. X.LP
  409. XOnly the UDP transport mechanism can use
  410. X.LW registerrpc() ;
  411. Xthus, it is always safe in conjunction with calls generated by
  412. X.LW callrpc() .
  413. X.LP
  414. XWarning: the UDP transport mechanism can only deal with
  415. Xarguments and results less than 8K bytes in length.
  416. X.NH 2
  417. XAssigning Program Numbers
  418. X.LP
  419. XProgram numbers are assigned in groups of 0x20000000 (536870912)
  420. Xaccording to the following chart:
  421. X.BS
  422. X.LS
  423. X       0 - 1fffffff    defined by sun
  424. X20000000 - 3fffffff    defined by user
  425. X40000000 - 5fffffff    transient
  426. X60000000 - 7fffffff    reserved
  427. X80000000 - 9fffffff    reserved
  428. Xa0000000 - bfffffff    reserved
  429. Xc0000000 - dfffffff    reserved
  430. Xe0000000 - ffffffff    reserved
  431. X.Lf
  432. X.BE
  433. XSun Microsystems administers the first group of numbers,
  434. Xwhich should be identical for all Sun customers.
  435. XIf a customer develops an application that might be of general interest,
  436. Xthat application should be given an assigned number in the first range.
  437. XThe second group of numbers is reserved for specific customer applications.
  438. XThis range is intended primarily for debugging new programs.
  439. XThe third group is reserved for applications that
  440. Xgenerate program numbers dynamically.
  441. XThe final groups are reserved for future use, and should not be used.
  442. X.LP
  443. XTo register a protocol specification,
  444. Xsend a request by network mail to
  445. X.LW sun!rpc ,
  446. Xor write to:
  447. X.DS
  448. XRPC Administrator
  449. XSun Microsystems
  450. X2550 Garcia Ave.
  451. XMountain View, CA 94043
  452. X.DE
  453. XPlease include a complete protocol specification,
  454. Xsimilar to those in this manual for NFS and YP.
  455. XYou will be given a unique program number in return.
  456. X.NH 2
  457. XPassing Arbitrary Data Types
  458. X.LP
  459. XIn the previous example, the RPC call passes a single
  460. X.LW "unsigned long" .
  461. XRPC can handle arbitrary data structures, regardless of
  462. Xdifferent machines' byte orders or structure layout conventions,
  463. Xby always converting them to a network standard called
  464. X.I "eXternal Data Representation"
  465. X(XDR) before
  466. Xsending them over the wire.
  467. XThe process of converting from a particular machine representation
  468. Xto XDR format is called
  469. X.I serializing ,
  470. Xand the reverse process is called
  471. X.I deserializing .
  472. XThe type field parameters of
  473. X.LW callrpc()
  474. Xand
  475. X.LW registerrpc()
  476. Xcan be a built-in procedure like
  477. X.LW xdr_u_long()
  478. Xin the previous example, or a user supplied one.
  479. XXDR has these built-in type routines:
  480. X.BS
  481. X.LS
  482. Xxdr_int()      xdr_u_int()      xdr_enum()
  483. Xxdr_long()     xdr_u_long()     xdr_bool()
  484. Xxdr_short()    xdr_u_short()    xdr_string()
  485. X.Lf
  486. X.BE
  487. XAs an example of a user-defined type routine,
  488. Xif you wanted to send the structure
  489. X.BS
  490. X.LS
  491. Xstruct simple {
  492. X    int a;
  493. X    short b;
  494. X} simple;
  495. X.Lf
  496. X.BE
  497. Xthen you would call
  498. X.LW callrpc()
  499. Xas
  500. X.BS
  501. X.LS
  502. Xcallrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
  503. X        xdr_simple, &simple ...);
  504. X.Lf
  505. X.BE
  506. Xwhere
  507. X.LW xdr_simple()
  508. Xis written as:
  509. X.BS
  510. X.LS
  511. X#include <rpc/rpc.h>
  512. X.sp.5
  513. Xxdr_simple(xdrsp, simplep)
  514. X    XDR *xdrsp;
  515. X    struct simple *simplep;
  516. X{
  517. X    if (!xdr_int(xdrsp, &simplep->a))
  518. X        return (0);
  519. X    if (!xdr_short(xdrsp, &simplep->b))
  520. X        return (0);
  521. X    return (1);
  522. X}
  523. X.Lf
  524. X.BE
  525. X.LP
  526. XAn XDR routine returns nonzero (true in the sense of C)
  527. Xif it completes successfully, and zero otherwise.
  528. XA complete description of XDR is in the
  529. X.I "XDR Protocol Specification" ,
  530. Xso this section only gives a few examples of XDR implementation.
  531. X.LP
  532. XIn addition to the built-in primitives,
  533. Xthere are also the prefabricated building blocks:
  534. X.BS
  535. X.LS
  536. Xxdr_array()       xdr_bytes()
  537. Xxdr_reference()   xdr_union()
  538. X.Lf
  539. X.BE
  540. XTo send a variable array of integers,
  541. Xyou might package them up as a structure like this
  542. X.BS
  543. X.LS
  544. Xstruct varintarr {
  545. X    int *data;
  546. X    int arrlnth;
  547. X} arr;
  548. X.Lf
  549. X.BE
  550. Xand make an RPC call such as
  551. X.BS
  552. X.LS
  553. Xcallrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
  554. X        xdr_varintarr, &arr...);
  555. X.Lf
  556. X.BE
  557. Xwith
  558. X.LW xdr_varintarr()
  559. Xdefined as:
  560. X.BS
  561. X.LS
  562. Xxdr_varintarr(xdrsp, arrp)
  563. X    XDR *xdrsp;
  564. X    struct varintarr *arrp;
  565. X{
  566. X    xdr_array(xdrsp, &arrp->data, &arrp->arrlnth, MAXLEN,
  567. X        sizeof(int), xdr_int);
  568. X}
  569. X.Lf
  570. X.BE
  571. XThis routine takes as parameters the XDR handle,
  572. Xa pointer to the array, a pointer to the size of the array,
  573. Xthe maximum allowable array size,
  574. Xthe size of each array element,
  575. Xand an XDR routine for handling each array element.
  576. X.LP
  577. XIf the size of the array is known in advance, then
  578. Xthe following could also be used to send
  579. Xout an array of length
  580. X.LW SIZE :
  581. X.BS
  582. X.LS
  583. Xint intarr[SIZE];
  584. X.sp.5
  585. Xxdr_intarr(xdrsp, intarr)
  586. X    XDR *xdrsp;
  587. X    int intarr[];
  588. X{
  589. X    int i;
  590. X.sp.5
  591. X    for (i = 0; i < SIZE; i++) {
  592. X        if (!xdr_int(xdrsp, &intarr[i]))
  593. X            return (0);
  594. X    }
  595. X    return (1);
  596. X}
  597. X.Lf
  598. X.BE
  599. X.LP
  600. XXDR always converts quantities to 4-byte multiples when deserializing.
  601. XThus, if either of the examples above involved characters
  602. Xinstead of integers, each character would occupy 32 bits.
  603. XThat is the reason for the XDR routine
  604. X.LW xdr_bytes() ,
  605. Xwhich is like
  606. X.LW xdr_array()
  607. Xexcept that it packs characters;
  608. X.LW xdr_bytes()
  609. Xhas four parameters, similar to the first four parameters of
  610. X.LW xdr_array() .
  611. XFor null-terminated strings, there is also the
  612. X.LW xdr_string()
  613. Xroutine, which is the same as
  614. X.LW xdr_bytes()
  615. Xwithout the length parameter.
  616. XOn serializing it gets the string length from
  617. X.LW strlen() ,
  618. Xand on deserializing it creates a null-terminated string.
  619. X.LP
  620. XHere is a final example that calls the previously written
  621. X.LW xdr_simple()
  622. Xas well as the built-in functions
  623. X.LW xdr_string()
  624. Xand
  625. X.LW xdr_reference() ,
  626. Xwhich chases pointers:
  627. X.BS
  628. X.LS
  629. Xstruct finalexample {
  630. X    char *string;
  631. X    struct simple *simplep;
  632. X} finalexample;
  633. X.sp.5
  634. Xxdr_finalexample(xdrsp, finalp)
  635. X    XDR *xdrsp;
  636. X    struct finalexample *finalp;
  637. X{
  638. X    int i;
  639. X.sp.5
  640. X    if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN))
  641. X        return (0);
  642. X    if (!xdr_reference(xdrsp, &finalp->simplep,
  643. X      sizeof(struct simple), xdr_simple);
  644. X        return (0);
  645. X    return (1);
  646. X}
  647. X.Lf
  648. X.BE
  649. X.bp
  650. X.NH
  651. XLowest Layer of RPC
  652. X.LP
  653. XIn the examples given so far,
  654. XRPC takes care of many details automatically for you.
  655. XIn this section, we'll show you how you can change the defaults
  656. Xby using lower layers of the RPC library.
  657. XIt is assumed that you are familiar with sockets
  658. Xand the system calls for dealing with them.
  659. XIf not, consult the
  660. X.I "IPC Primer" .
  661. X.LP
  662. XThere are several occasions when you may need to use lower layers of RPC.
  663. XFirst, you may need to use TCP.
  664. XThe higher layer uses UDP,
  665. Xwhich restricts RPC calls to 8K bytes of data.
  666. XUsing TCP permits calls to send long streams of data.
  667. XFor an example, see section 5.2 below.
  668. XSecond, you may want to allocate and free memory
  669. Xwhile serializing or deserializing with XDR routines.
  670. XThere is no call at the higher level to let you free memory explicitly.
  671. XFor more explanation, see section 3.2 below.
  672. XThird, you may need to perform authentication
  673. Xon either the client or server side,
  674. Xby supplying credentials or verifying them.
  675. XSee the explanation in section 4.4 below.
  676. X.NH 2
  677. XMore on the Server Side
  678. X.LP
  679. XThe server for the
  680. X.LW nusers
  681. Xprogram shown below does the same thing as the one using
  682. X.LW registerrpc()
  683. Xabove, but is written using a lower layer of the RPC package:
  684. X.BS
  685. X.LS no
  686. X#include <stdio.h>
  687. X#include <rpc/rpc.h>
  688. X#include <rpcsvc/rusers.h>
  689. X.sp.5
  690. Xmain()
  691. X{
  692. X    SVCXPRT *transp;
  693. X    int nuser();
  694. X.sp.5
  695. X    transp = svcudp_create(RPC_ANYSOCK);
  696. X    if (transp == NULL){
  697. X        fprintf(stderr, "can't create an RPC server\en");
  698. X        exit(1);
  699. X    }
  700. X    pmap_unset(RUSERSPROG, RUSERSVERS);
  701. X    if (!svc_register(transp, RUSERSPROG, RUSERSVERS,
  702. X              nuser, IPPROTO_UDP)) {
  703. X        fprintf(stderr, "can't register RUSER service\en");
  704. X        exit(1);
  705. X    }
  706. X    svc_run();  /* never returns */
  707. X    fprintf(stderr, "should never reach this point\en");
  708. X}
  709. X.sp.5
  710. Xnuser(rqstp, tranp)
  711. X    struct svc_req *rqstp;
  712. X    SVCXPRT *transp;
  713. X{
  714. X    unsigned long nusers;
  715. X.sp.5
  716. X    switch (rqstp->rq_proc) {
  717. X    case NULLPROC:
  718. X        if (!svc_sendreply(transp, xdr_void, 0)) {
  719. X            fprintf(stderr, "can't reply to RPC call\en");
  720. X            exit(1);
  721. X        }
  722. X        return;
  723. X    case RUSERSPROC_NUM:
  724. X        /*
  725. X         * code here to compute the number of users
  726. X         * and put in variable nusers
  727. X         */
  728. X        if (!svc_sendreply(transp, xdr_u_long, &nusers) {
  729. X            fprintf(stderr, "can't reply to RPC call\en");
  730. X            exit(1);
  731. X        }
  732. X        return;
  733. X    default:
  734. X        svcerr_noproc(transp);
  735. X        return;
  736. X    }
  737. X}
  738. X.Lf
  739. X.BE
  740. X.LP
  741. XFirst, the server gets a transport handle, which is used
  742. Xfor sending out RPC messages.
  743. X.LW registerrpc()
  744. Xuses
  745. X.LW svcudp_create()
  746. Xto get a UDP handle.
  747. XIf you require a reliable protocol, call
  748. X.LW svctcp_create()
  749. Xinstead.
  750. XIf the argument to
  751. X.LW svcudp_create()
  752. Xis
  753. X.LW RPC_ANYSOCK ,
  754. Xthe RPC library creates a socket
  755. Xon which to send out RPC calls.
  756. XOtherwise,
  757. X.LW svcudp_create()
  758. Xexpects its argument to be a valid socket number.
  759. XIf you specify your own socket, it can be bound or unbound.
  760. XIf it is bound to a port by the user, the port numbers of
  761. X.LW svcudp_create()
  762. Xand
  763. X.LW clntudp_create()
  764. X(the low-level client routine) must match.
  765. X.LP
  766. XWhen the user specifies
  767. X.LW RPC_ANYSOCK
  768. Xfor a socket or gives an unbound socket,
  769. Xthe system determines port numbers in the following way:
  770. Xwhen a server starts up,
  771. Xit advertises to a port mapper demon on its local machine,
  772. Xwhich picks a port number for the RPC procedure
  773. Xif the socket specified to
  774. X.LW svcudp_create()
  775. Xisn't already bound.
  776. XWhen the
  777. X.LW clntudp_create()
  778. Xcall is made with an unbound socket,
  779. Xthe system queries the port mapper on
  780. Xthe machine to which the call is being made,
  781. Xand gets the appropriate port number.
  782. XIf the port mapper is not running
  783. Xor has no port corresponding to the RPC call,
  784. Xthe RPC call fails.
  785. XUsers can make RPC calls
  786. Xto the port mapper themselves.
  787. XThe appropriate procedure
  788. Xnumbers are in the include file
  789. X.LW <rpc/pmap_prot.h> .
  790. X.LP
  791. XAfter creating an
  792. X.LW SVCXPRT ,
  793. Xthe next step is to call
  794. X.LW pmap_unset()
  795. Xso that if the
  796. X.LW nusers
  797. Xserver crashed earlier,
  798. Xany previous trace of it is erased before restarting.
  799. XMore precisely,
  800. X.LW pmap_unset()
  801. Xerases the entry for
  802. X.LW RUSERSPROG
  803. Xfrom the port mapper's tables.
  804. X.LP
  805. XFinally, we associate the program number for
  806. X.LW nusers
  807. Xwith the procedure
  808. X.LW nuser() .
  809. XThe final argument to
  810. X.LW svc_register()
  811. Xis normally the protocol being used,
  812. Xwhich, in this case, is
  813. X.LW IPPROTO_UDP .
  814. XNotice that unlike
  815. X.LW registerrpc() ,
  816. Xthere are no XDR routines involved
  817. Xin the registration process.
  818. XAlso, registration is done on the program,
  819. Xrather than procedure, level.
  820. X.LP
  821. XThe user routine
  822. X.LW nuser()
  823. Xmust call and dispatch the appropriate XDR routines
  824. Xbased on the procedure number.
  825. XNote that
  826. Xtwo things are handled by
  827. X.LW nuser()
  828. Xthat
  829. X.LW registerrpc()
  830. Xhandles automatically.
  831. XThe first is that procedure
  832. X.LW NULLPROC
  833. X(currently zero) returns with no arguments.
  834. XThis can be used as a simple test
  835. Xfor detecting if a remote program is running.
  836. XSecond, there is a check for invalid procedure numbers.
  837. XIf one is detected,
  838. X.LW svcerr_noproc()
  839. Xis called to handle the error.
  840. X.LP
  841. XThe user service routine serializes the results and returns
  842. Xthem to the RPC caller via
  843. X.LW svc_sendreply() .
  844. XIts first parameter is the
  845. X.LW SVCXPRT
  846. Xhandle, the second is the XDR routine,
  847. Xand the third is a pointer to the data to be returned.
  848. XNot illustrated above is how a server
  849. Xhandles an RPC program that passes data.
  850. XAs an example, we can add a procedure
  851. X.LW RUSERSPROC_BOOL ,
  852. Xwhich has an argument
  853. X.LW nusers ,
  854. Xand returns
  855. X.LW TRUE
  856. Xor
  857. X.LW FALSE
  858. Xdepending on whether there are nusers logged on.
  859. XIt would look like this:
  860. X.BS
  861. X.LS
  862. Xcase RUSERSPROC_BOOL: {
  863. X    int bool;
  864. X    unsigned nuserquery;
  865. X.sp.5
  866. X    if (!svc_getargs(transp, xdr_u_int, &nuserquery) {
  867. X        svcerr_decode(transp);
  868. X        return;
  869. X    }
  870. X    /*
  871. X     * code to set nusers = number of users
  872. X     */
  873. X    if (nuserquery == nusers)
  874. X        bool = TRUE;
  875. X    else
  876. X        bool = FALSE;
  877. X    if (!svc_sendreply(transp, xdr_bool, &bool){
  878. X         fprintf(stderr, "can't reply to RPC call\en");
  879. X         exit(1);
  880. X    }
  881. X    return;
  882. X}
  883. X.Lf
  884. X.BE
  885. X.LP
  886. XThe relevant routine is
  887. X.LW svc_getargs() ,
  888. Xwhich takes an
  889. X.LW SVCXPRT
  890. Xhandle, the XDR routine,
  891. Xand a pointer to where the input is to be placed as arguments.
  892. X.NH 2
  893. XMemory Allocation with XDR
  894. X.LP
  895. XXDR routines not only do input and output,
  896. Xthey also do memory allocation.
  897. XThis is why the second parameter of
  898. X.LW xdr_array()
  899. Xis a pointer to an array, rather than the array itself.
  900. XIf it is
  901. X.LW NULL ,
  902. Xthen
  903. X.LW xdr_array()
  904. Xallocates space for the array and returns a pointer to it,
  905. Xputting the size of the array in the third argument.
  906. XAs an example, consider the following XDR routine
  907. X.LW xdr_chararr1() ,
  908. Xwhich deals with a fixed array of bytes with length
  909. X.LW SIZE :
  910. X.BS
  911. X.LS
  912. Xxdr_chararr1(xdrsp, chararr)
  913. X    XDR *xdrsp;
  914. X    char chararr[];
  915. X{
  916. X    char *p;
  917. X    int len;
  918. X.sp.5
  919. X    p = chararr;
  920. X    len = SIZE;
  921. X    return (xdr_bytes(xdrsp, &p, &len, SIZE));
  922. X}
  923. X.Lf
  924. X.BE
  925. XIt might be called from a server like this,
  926. X.BS
  927. X.LS
  928. Xchar chararr[SIZE];
  929. X.sp.5
  930. Xsvc_getargs(transp, xdr_chararr1, chararr);
  931. X.Lf
  932. X.BE
  933. Xwhere
  934. X.LW chararr
  935. Xhas already allocated space.
  936. XIf you want XDR to do the allocation,
  937. Xyou would have to rewrite this routine in the following way:
  938. X.BS
  939. X.LS
  940. Xxdr_chararr2(xdrsp, chararrp)
  941. X    XDR *xdrsp;
  942. X    char **chararrp;
  943. X{
  944. X    int len;
  945. X.sp.5
  946. X    len = SIZE;
  947. X    return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));
  948. X}
  949. X.Lf
  950. X.BE
  951. XThen the RPC call might look like this:
  952. X.BS
  953. X.LS
  954. Xchar *arrptr;
  955. X.sp.5
  956. Xarrptr = NULL;
  957. Xsvc_getargs(transp, xdr_chararr2, &arrptr);
  958. X/*
  959. X * use the result here
  960. X */
  961. Xsvc_freeargs(transp, xdr_chararr2, &arrptr);
  962. X.Lf
  963. X.BE
  964. XAfter using the character array, it can be freed with
  965. X.LW svc_freeargs() .
  966. XIn the routine
  967. X.LW xdr_finalexample()
  968. Xgiven earlier, if
  969. X.LW finalp->string
  970. Xwas
  971. X.LW NULL
  972. Xin the call
  973. X.BS
  974. X.LS
  975. Xsvc_getargs(transp, xdr_finalexample, &finalp);
  976. X.Lf
  977. X.BE
  978. Xthen
  979. X.BS
  980. X.LS
  981. Xsvc_freeargs(xdrsp, xdr_finalexample, &finalp);
  982. X.Lf
  983. X.BE
  984. Xfrees the array allocated to hold
  985. X.LW finalp->string ;
  986. Xotherwise, it frees nothing.
  987. XThe same is true for
  988. X.LW finalp->simplep .
  989. X.LP
  990. XTo summarize, each XDR routine is responsible
  991. Xfor serializing, deserializing, and allocating memory.
  992. XWhen an XDR routine is called from
  993. X.LW callrpc() ,
  994. Xthe serializing part is used.
  995. XWhen called from
  996. X.LW svc_getargs() ,
  997. Xthe deserializer is used.
  998. XAnd when called from
  999. X.LW svc_freeargs() ,
  1000. Xthe memory deallocator is used.
  1001. XWhen building simple examples like those in this section,
  1002. Xa user doesn't have to worry about the three modes.
  1003. XThe XDR reference manual has examples of more
  1004. Xsophisticated XDR routines that
  1005. Xdetermine which of the three modes they are in
  1006. Xto function correctly.
  1007. X.NH 2
  1008. XThe Calling Side
  1009. X.LP
  1010. XWhen you use
  1011. X.LW callrpc() ,
  1012. Xyou have no control over the RPC delivery
  1013. Xmechanism or the socket used to transport the data.
  1014. XTo illustrate the layer of RPC that lets you adjust these
  1015. Xparameters, consider the following code to call the
  1016. X.LW nusers
  1017. Xservice:
  1018. X.BS
  1019. X.LS no
  1020. X#include <stdio.h>
  1021. X#include <rpc/rpc.h>
  1022. X#include <rpcsvc/rusers.h>
  1023. X#include <sys/socket.h>
  1024. X#include <sys/time.h>
  1025. X#include <netdb.h>
  1026. X.sp.5
  1027. Xmain(argc, argv)
  1028. X    int argc;
  1029. X    char **argv;
  1030. X{
  1031. X    struct hostent *hp;
  1032. X    struct timeval pertry_timeout, total_timeout;
  1033. X    struct sockaddr_in server_addr;
  1034. X    int addrlen, sock = RPC_ANYSOCK;
  1035. X    register CLIENT *client;
  1036. X    enum clnt_stat clnt_stat;
  1037. X    unsigned long nusers;
  1038. X.sp.5
  1039. X    if (argc < 2) {
  1040. X        fprintf(stderr, "usage: nusers hostname\en");
  1041. X        exit(-1);
  1042. X    }
  1043. X    if ((hp = gethostbyname(argv[1])) == NULL) {
  1044. X        fprintf(stderr, "can't get addr for %s\en",argv[1]);
  1045. X        exit(-1);
  1046. X    }
  1047. X    pertry_timeout.tv_sec = 3;
  1048. X    pertry_timeout.tv_usec = 0;
  1049. X    addrlen = sizeof(struct sockaddr_in);
  1050. X    bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
  1051. X        hp->h_length);
  1052. X    server_addr.sin_family = AF_INET;
  1053. X    server_addr.sin_port =  0;
  1054. X    if ((client = clntudp_create(&server_addr, RUSERSPROG,
  1055. X      RUSERSVERS, pertry_timeout, &sock)) == NULL) {
  1056. X        clnt_pcreateerror("clntudp_create");
  1057. X        exit(-1);
  1058. X    }
  1059. X    total_timeout.tv_sec = 20;
  1060. X    total_timeout.tv_usec = 0;
  1061. X    clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void,
  1062. X        0, xdr_u_long, &nusers, total_timeout);
  1063. X    if (clnt_stat != RPC_SUCCESS) {
  1064. X        clnt_perror(client, "rpc");
  1065. X        exit(-1);
  1066. X    }
  1067. X    clnt_destroy(client);
  1068. X}
  1069. X.Lf
  1070. X.BE
  1071. XThe low-level version of
  1072. X.LW callrpc()
  1073. Xis
  1074. X.LW clnt_call() ,
  1075. Xwhich takes a
  1076. X.LW CLIENT
  1077. Xpointer rather than a host name.  The parameters to
  1078. X.LW clnt_call()
  1079. Xare a
  1080. X.LW CLIENT
  1081. Xpointer, the procedure number,
  1082. Xthe XDR routine for serializing the argument,
  1083. Xa pointer to the argument,
  1084. Xthe XDR routine for deserializing the return value,
  1085. Xa pointer to where the return value will be placed,
  1086. Xand the time in seconds to wait for a reply.
  1087. X.LP
  1088. XThe
  1089. X.LW CLIENT
  1090. Xpointer is encoded with the transport mechanism.
  1091. X.LW callrpc()
  1092. Xuses UDP, thus it calls
  1093. X.LW clntudp_create()
  1094. Xto get a
  1095. X.LW CLIENT
  1096. Xpointer.  To get TCP (Transport Control Protocol), you would use
  1097. X.LW clnttcp_create() .
  1098. X.LP
  1099. XThe parameters to
  1100. X.LW clntudp_create()
  1101. Xare the server address, the length of the server address,
  1102. Xthe program number, the version number,
  1103. Xa timeout value (between tries), and a pointer to a socket.
  1104. XThe final argument to
  1105. X.LW clnt_call()
  1106. Xis the total time to wait for a response.
  1107. XThus, the number of tries is the
  1108. X.LW clnt_call()
  1109. Xtimeout divided by the
  1110. X.LW clntudp_create()
  1111. Xtimeout.
  1112. X.LP
  1113. XThere is one thing to note when using the
  1114. X.LW clnt_destroy()
  1115. Xcall.
  1116. XIt deallocates any space associated with the
  1117. X.LW CLIENT
  1118. Xhandle, but it does not close the socket associated with it,
  1119. Xwhich was passed as an argument to
  1120. X.LW clntudp_create() .
  1121. XThe reason is that if
  1122. Xthere are multiple client handles using the same socket,
  1123. Xthen it is possible to close one handle
  1124. Xwithout destroying the socket that other handles
  1125. Xare using.
  1126. X.LP
  1127. XTo make a stream connection, the call to
  1128. X.LW clntudp_create()
  1129. Xis replaced with a call to
  1130. X.LW clnttcp_create() .
  1131. X.BS
  1132. X.LS
  1133. Xclnttcp_create(&server_addr, prognum, versnum, &socket,
  1134. X               inputsize, outputsize);
  1135. X.Lf
  1136. X.BE
  1137. XThere is no timeout argument; instead, the receive and send buffer
  1138. Xsizes must be specified.  When the
  1139. X.LW clnttcp_create()
  1140. Xcall is made, a TCP connection is established.
  1141. XAll RPC calls using that
  1142. X.LW CLIENT
  1143. Xhandle would use this connection.
  1144. XThe server side of an RPC call using TCP has
  1145. X.LW svcudp_create()
  1146. Xreplaced by
  1147. X.LW svctcp_create() .
  1148. X.bp
  1149. X.NH
  1150. XOther RPC Features
  1151. X.LP
  1152. XThis section discusses some other aspects of RPC
  1153. Xthat are occasionally useful.
  1154. X.NH 2
  1155. XSelect on the Server Side
  1156. X.LP
  1157. XSuppose a process is processing RPC requests
  1158. Xwhile performing some other activity.
  1159. XIf the other activity involves periodically updating a data structure,
  1160. Xthe process can set an alarm signal before calling
  1161. X.LW svc_run() .
  1162. XBut if the other activity
  1163. Xinvolves waiting on a a file descriptor, the
  1164. X.LW svc_run()
  1165. Xcall won't work.
  1166. XThe code for
  1167. X.LW svc_run()
  1168. Xis as follows:
  1169. X.BS
  1170. X.LS
  1171. Xvoid
  1172. Xsvc_run()
  1173. X{
  1174. X    int readfds;
  1175. X.sp.5
  1176. X    for (;;) {
  1177. X        readfds = svc_fds;
  1178. X        switch (select(32, &readfds, NULL, NULL, NULL)) {
  1179. X.sp.5
  1180. X        case -1:
  1181. X            if (errno == EINTR)
  1182. X                continue;
  1183. X            perror("rstat: select");
  1184. X            return;
  1185. X        case 0:
  1186. X            break;
  1187. X        default:
  1188. X            svc_getreq(readfds);
  1189. X        }
  1190. X    }
  1191. X}
  1192. X.Lf
  1193. X.BE
  1194. X.LP
  1195. XYou can bypass
  1196. X.LW svc_run()
  1197. Xand call
  1198. X.LW svc_getreq()
  1199. Xyourself.
  1200. XAll you need to know are the file descriptors
  1201. Xof the socket(s) associated with the programs you are waiting on.
  1202. XThus you can have your own
  1203. X.LW select()
  1204. Xthat waits on both the RPC socket,
  1205. Xand your own descriptors.
  1206. X.NH 2
  1207. XBroadcast RPC
  1208. X.LP
  1209. XThe
  1210. X.I portmapper
  1211. Xis a daemon that converts RPC program numbers
  1212. Xinto DARPA protocol port numbers; see
  1213. X.LW portmap (8).
  1214. XYou can't do broadcast RPC without the portmapper,
  1215. X.LW pmap ,
  1216. Xin conjunction with standard RPC protocols.
  1217. XHere are the main differences between
  1218. Xbroadcast RPC and normal RPC calls:
  1219. X.IP 1.
  1220. XNormal RPC expects one answer, whereas
  1221. Xbroadcast RPC expects many answers
  1222. X(one or more answer from each responding machine).
  1223. X.IP 2.
  1224. XBroadcast RPC can only be supported by packet-oriented (connectionless)
  1225. Xtransport protocols like UPD/IP.
  1226. X.IP 3.
  1227. XThe implementation of broadcast RPC
  1228. Xtreats all unsuccessful responses as garbage by filtering them out.
  1229. XThus, if there is a version mismatch between the
  1230. Xbroadcaster and a remote service,
  1231. Xthe user of broadcast RPC never knows.
  1232. X.IP 4.
  1233. XAll broadcast messages are sent to the portmap port.
  1234. XThus, only services that register themselves with their portmapper
  1235. Xare accessible via the broadcast RPC mechanism.
  1236. X.NH 3
  1237. XBroadcast RPC Synopsis
  1238. X.LP
  1239. X.BS
  1240. X.LS
  1241. X#include <rpc/pmap_clnt.h>
  1242. X.sp.5
  1243. Xenum clnt_stat    clnt_stat;
  1244. X.sp.5
  1245. Xclnt_stat =
  1246. Xclnt_broadcast(prog, vers, proc, xargs, argsp, xresults,
  1247. X    resultsp, eachresult)
  1248. Xu_long        prog;        /* program number */
  1249. Xu_long        vers;        /* version number */
  1250. Xu_long        proc;        /* procedure number */
  1251. Xxdrproc_t    xargs;        /* xdr routine for args */
  1252. Xcaddr_t        argsp;        /* pointer to args */
  1253. Xxdrproc_t    xresults;    /* xdr routine for results */
  1254. Xcaddr_t        resultsp;    /* pointer to results */
  1255. Xbool_t (*eachresult)();    /* call with each result gotten */
  1256. X.Lf
  1257. X.BE
  1258. XThe procedure
  1259. X.LW eachresult()
  1260. Xis called each time a valid result is obtained.
  1261. XIt returns a boolean that indicates
  1262. Xwhether or not the client wants more responses.
  1263. X.BS
  1264. X.LS
  1265. Xbool_t            done;
  1266. X.sp.5
  1267. Xdone =
  1268. Xeachresult(resultsp, raddr)
  1269. Xcaddr_t resultsp;
  1270. Xstruct sockaddr_in *raddr;  /* addr of responding machine */
  1271. X.Lf
  1272. X.BE
  1273. XIf
  1274. X.LW done
  1275. Xis
  1276. X.LW TRUE ,
  1277. Xthen broadcasting stops and
  1278. X.LW clnt_broadcast()
  1279. Xreturns successfully.
  1280. XOtherwise, the routine waits for another response.
  1281. XThe request is rebroadcast
  1282. Xafter a few seconds of waiting.
  1283. XIf no responses come back,
  1284. Xthe routine returns with
  1285. X.LW RPC_TIMEDOUT .
  1286. XTo interpret
  1287. X.LW clnt_stat
  1288. Xerrors, feed the error code to
  1289. X.LW clnt_perrno() .
  1290. X.NH 2
  1291. XBatching
  1292. X.LP
  1293. XThe RPC architecture is designed so that clients send a call message,
  1294. Xand wait for servers to reply that the call succeeded.
  1295. XThis implies that clients do not compute
  1296. Xwhile servers are processing a call.
  1297. XThis is inefficient if the client does not want or need
  1298. Xan acknowledgement for every message sent.
  1299. XIt is possible for clients to continue computing
  1300. Xwhile waiting for a response,
  1301. Xusing RPC batch facilities.
  1302. X.LP
  1303. XRPC messages can be placed in a ``pipeline'' of calls
  1304. Xto a desired server; this is called batching.
  1305. XBatching assumes that:
  1306. X1) each RPC call in the pipeline requires no response from the server,
  1307. Xand the server does not send a response message; and
  1308. X2) the pipeline of calls is transported on a reliable
  1309. Xbyte stream transport such as TCP/IP.
  1310. XSince the server does not respond to every call,
  1311. Xthe client can generate new calls in parallel
  1312. Xwith the server executing previous calls.
  1313. XFurthermore, the TCP/IP implementation can buffer up
  1314. Xmany call messages, and send them to the server in one
  1315. X.LW write()
  1316. Xsystem call.  This overlapped execution
  1317. Xgreatly decreases the interprocess communication overhead of
  1318. Xthe client and server processes,
  1319. Xand the total elapsed time of a series of calls.
  1320. X.LP
  1321. XSince the batched calls are buffered,
  1322. Xthe client should eventually do a legitimate call
  1323. Xin order to flush the pipeline.
  1324. X.LP
  1325. XA contrived example of batching follows.
  1326. XAssume a string rendering service (like a window system)
  1327. Xhas two similar calls: one renders a string and returns void results,
  1328. Xwhile the other renders a string and remains silent.
  1329. XThe service (using the TCP/IP transport) may look like:
  1330. X.BS
  1331. X.LS no
  1332. X#include <stdio.h>
  1333. X#include <rpc/rpc.h>
  1334. X#include <rpcsvc/windows.h>
  1335. X.sp.5
  1336. Xvoid windowdispatch();
  1337. X.sp.5
  1338. Xmain()
  1339. X{
  1340. X    SVCXPRT *transp;
  1341. X.sp.5
  1342. X    transp = svctcp_create(RPC_ANYSOCK, 0, 0);
  1343. X    if (transp == NULL){
  1344. X        fprintf(stderr, "can't create an RPC server\en");
  1345. X        exit(1);
  1346. X    }
  1347. X    pmap_unset(WINDOWPROG, WINDOWVERS);
  1348. X    if (!svc_register(transp, WINDOWPROG, WINDOWVERS,
  1349. X      windowdispatch, IPPROTO_TCP)) {
  1350. X        fprintf(stderr, "can't register WINDOW service\en");
  1351. X        exit(1);
  1352. X    }
  1353. X    svc_run();  /* never returns */
  1354. X    fprintf(stderr, "should never reach this point\en");
  1355. X}
  1356. X.sp.5
  1357. Xvoid
  1358. Xwindowdispatch(rqstp, transp)
  1359. X    struct svc_req *rqstp;
  1360. X    SVCXPRT *transp;
  1361. X{
  1362. X    char *s = NULL;
  1363. X.sp.5
  1364. X    switch (rqstp->rq_proc) {
  1365. X    case NULLPROC:
  1366. X        if (!svc_sendreply(transp, xdr_void, 0)) {
  1367. X            fprintf(stderr, "can't reply to RPC call\en");
  1368. X            exit(1);
  1369. X        }
  1370. X        return;
  1371. X    case RENDERSTRING:
  1372. X        if (!svc_getargs(transp, xdr_wrapstring, &s)) {
  1373. X            fprintf(stderr, "can't decode arguments\en");
  1374. X            /*
  1375. X             * tell caller he screwed up
  1376. X             */
  1377. X            svcerr_decode(transp);
  1378. X            break;
  1379. X        }
  1380. X        /*
  1381. X         * call here to render the string s
  1382. X         */
  1383. X        if (!svc_sendreply(transp, xdr_void, NULL)) {
  1384. X            fprintf(stderr, "can't reply to RPC call\en");
  1385. X            exit(1);
  1386. X        }
  1387. X        break;
  1388. X    case RENDERSTRING_BATCHED:
  1389. X        if (!svc_getargs(transp, xdr_wrapstring, &s)) {
  1390. X            fprintf(stderr, "can't decode arguments\en");
  1391. X            /*
  1392. X             * we are silent in the face of protocol errors
  1393. X             */
  1394. X            break;
  1395. X        }
  1396. X        /*
  1397. X         * call here to render string s, but send no reply!
  1398. X         */
  1399. X        break;
  1400. X    default:
  1401. X        svcerr_noproc(transp);
  1402. X        return;
  1403. X    }
  1404. X    /*
  1405. X     * now free string allocated while decoding arguments
  1406. X     */
  1407. X    svc_freeargs(transp, xdr_wrapstring, &s);
  1408. X}
  1409. X.Lf
  1410. X.BE
  1411. XOf course the service could have one procedure
  1412. Xthat takes the string and a boolean
  1413. Xto indicate whether or not the procedure should respond.
  1414. X.LP
  1415. XIn order for a client to take advantage of batching,
  1416. Xthe client must perform RPC calls on a TCP-based transport
  1417. Xand the actual calls must have the following attributes:
  1418. X1) the result's XDR routine must be zero
  1419. X.LW NULL ), (
  1420. Xand 2) the RPC call's timeout must be zero.
  1421. X.LP
  1422. XHere is an example of a client that uses batching
  1423. Xto render a bunch of strings;
  1424. Xthe batching is flushed when the client gets a null string:
  1425. X.BS
  1426. X.LS no
  1427. X#include <stdio.h>
  1428. X#include <rpc/rpc.h>
  1429. X#include <rpcsvc/windows.h>
  1430. X#include <sys/socket.h>
  1431. X#include <sys/time.h>
  1432. X#include <netdb.h>
  1433. X.sp.5
  1434. Xmain(argc, argv)
  1435. X    int argc;
  1436. X    char **argv;
  1437. X{
  1438. X    struct hostent *hp;
  1439. X    struct timeval pertry_timeout, total_timeout;
  1440. X    struct sockaddr_in server_addr;
  1441. X    int addrlen, sock = RPC_ANYSOCK;
  1442. X    register CLIENT *client;
  1443. X    enum clnt_stat clnt_stat;
  1444. X    char buf[1000], *s = buf;
  1445. X.sp.5
  1446. X    /* initial as in example 3.3
  1447. X     */
  1448. X    if ((client = clnttcp_create(&server_addr,
  1449. X      WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) {
  1450. X        perror("clnttcp_create");
  1451. X        exit(-1);
  1452. X    }
  1453. X    total_timeout.tv_sec = 0;
  1454. X    total_timeout.tv_usec = 0;
  1455. X    while (scanf("%s", s) != EOF) {
  1456. X        clnt_stat = clnt_call(client, RENDERSTRING_BATCHED,
  1457. X            xdr_wrapstring, &s, NULL, NULL, total_timeout);
  1458. X        if (clnt_stat != RPC_SUCCESS) {
  1459. X            clnt_perror(client, "batched rpc");
  1460. X            exit(-1);
  1461. X        }
  1462. X    }
  1463. X    /* now flush the pipeline
  1464. X     */
  1465. X    total_timeout.tv_sec = 20;
  1466. X    clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL,
  1467. X        xdr_void, NULL, total_timeout);
  1468. X    if (clnt_stat != RPC_SUCCESS) {
  1469. X        clnt_perror(client, "rpc");
  1470. X        exit(-1);
  1471. X    }
  1472. X    clnt_destroy(client);
  1473. X}
  1474. X.Lf
  1475. X.BE
  1476. XSince the server sends no message,
  1477. Xthe clients cannot be notified of any of the failures that may occur.
  1478. XTherefore, clients are on their own when it comes to handling errors.
  1479. X.LP
  1480. XThe above example was completed to render
  1481. Xall of the (2000) lines in the file
  1482. X.I /etc/termcap .
  1483. XThe rendering service did nothing but throw the lines away.
  1484. XThe example was run in the following four configurations:
  1485. X1) machine to itself, regular RPC;
  1486. X2) machine to itself, batched RPC;
  1487. X3) machine to another, regular RPC; and
  1488. X4) machine to another, batched RPC.
  1489. XThe results are as follows:
  1490. X1) 50 seconds;
  1491. X2) 16 seconds;
  1492. X3) 52 seconds;
  1493. X4) 10 seconds.
  1494. XRunning
  1495. X.LW fscanf()
  1496. Xon
  1497. X.I /etc/termcap
  1498. Xonly requires six seconds.
  1499. XThese timings show the advantage of protocols
  1500. Xthat allow for overlapped execution,
  1501. Xthough these protocols are often hard to design.
  1502. X.NH 2
  1503. XAuthentication
  1504. X.LP
  1505. XIn the examples presented so far,
  1506. Xthe caller never identified itself to the server,
  1507. Xand the server never required an ID from the caller.
  1508. XClearly, some network services, such as a network filesystem,
  1509. Xrequire stronger security than what has been presented so far.
  1510. X.LP
  1511. XIn reality, every RPC call is authenticated by
  1512. Xthe RPC package on the server, and similarly,
  1513. Xthe RPC client package generates and sends authentication parameters.
  1514. XJust as different transports (TCP/IP or UDP/IP)
  1515. Xcan be used when creating RPC clients and servers,
  1516. Xdifferent forms of authentication can be associated with RPC clients;
  1517. Xthe default authentication type used as a default is type
  1518. X.I none .
  1519. X.LP
  1520. XThe authentication subsystem of the RPC package is open ended.
  1521. XThat is, numerous types of authentication are easy to support.
  1522. XHowever, this section deals only with
  1523. X.I unix
  1524. Xtype authentication, which besides
  1525. X.I none
  1526. Xis the only supported type.
  1527. X.NH 3
  1528. XThe Client Side
  1529. X.LP
  1530. XWhen a caller creates a new RPC client handle as in:
  1531. X.BS
  1532. X.LS
  1533. Xclnt = clntudp_create(address, prognum, versnum,
  1534. X              wait, sockp)
  1535. X.Lf
  1536. X.BE
  1537. Xthe appropriate transport instance defaults
  1538. Xthe associate authentication handle to be
  1539. X.BS
  1540. X.LS
  1541. Xclnt->cl_auth = authnone_create();
  1542. X.Lf
  1543. X.BE
  1544. XThe RPC client can choose to use
  1545. X.I unix
  1546. Xstyle authentication by setting
  1547. X.LW clnt->cl_auth
  1548. Xafter creating the RPC client handle:
  1549. X.BS
  1550. X.LS
  1551. Xclnt->cl_auth = authunix_create_default();
  1552. X.Lf
  1553. X.BE
  1554. XThis causes each RPC call associated with
  1555. X.LW clnt
  1556. Xto carry with it the following authentication credentials structure:
  1557. X.BS
  1558. X.LS
  1559. X/*
  1560. X * Unix style credentials.
  1561. X */
  1562. Xstruct authunix_parms {
  1563. X    u_long     aup_time;    /* credentials creation time */
  1564. X    char *aup_machname;    /* host name where client is */
  1565. X    int     aup_uid;    /* client's UNIX effective uid */
  1566. X    int     aup_gid;    /* client's current group id */
  1567. X    u_int    aup_len;    /* element length of aup_gids */
  1568. X    int     *aup_gids;    /* array of groups user is in */
  1569. X};
  1570. X.Lf
  1571. X.BE
  1572. XThese fields are set by
  1573. X.LW authunix_create_default()
  1574. Xby invoking the appropriate system calls.
  1575. XSince the RPC user created this new style of authentication,
  1576. Xthe user is responsible for destroying it with:
  1577. X.BS
  1578. X.LS
  1579. Xauth_destroy(clnt->cl_auth);
  1580. X.Lf
  1581. X.BE
  1582. XThis should be done in all cases, to conserve memory.
  1583. X.NH 3
  1584. XThe Server Side
  1585. X.LP
  1586. XService implementors have a harder time dealing with authentication issues
  1587. Xsince the RPC package passes the service dispatch routine a request
  1588. Xthat has an arbitrary authentication style associated with it.
  1589. XConsider the fields of a request handle passed to a service dispatch routine:
  1590. X.BS
  1591. X.LS
  1592. X/*
  1593. X * An RPC Service request
  1594. X */
  1595. Xstruct svc_req {
  1596. X    u_long    rq_prog;        /* service program number */
  1597. X    u_long    rq_vers;        /* service protocol vers num */
  1598. X    u_long    rq_proc;        /* desired procedure number */
  1599. X    struct opaque_auth
  1600. X            rq_cred;        /* raw credentials from wire */
  1601. X    caddr_t rq_clntcred;    /* credentials (read only) */
  1602. X};
  1603. X.Lf
  1604. X.BE
  1605. XThe
  1606. X.LW rq_cred
  1607. Xis mostly opaque, except for one field of interest:
  1608. Xthe style of authentication credentials:
  1609. X.BS
  1610. X.LS
  1611. X/*
  1612. X * Authentication info.  Mostly opaque to the programmer.
  1613. X */
  1614. Xstruct opaque_auth {
  1615. X    enum_t    oa_flavor;    /* style of credentials */
  1616. X    caddr_t    oa_base;    /* address of more auth stuff */
  1617. X    u_int    oa_length;    /* not to exceed MAX_AUTH_BYTES */
  1618. X};
  1619. X.Lf
  1620. X.BE
  1621. XThe RPC package guarantees the following
  1622. Xto the service dispatch routine:
  1623. X.IP 1.
  1624. XThat the request's
  1625. X.LW rq_cred
  1626. Xis well formed.  Thus the service implementor may inspect the request's
  1627. X.LW rq_cred.oa_flavor
  1628. Xto determine which style of authentication the caller used.
  1629. XThe service implementor may also wish to inspect the other fields of
  1630. X.LW rq_cred
  1631. Xif the style is not one of the styles supported by the RPC package.
  1632. X.IP 2.
  1633. XThat the request's
  1634. X.LW rq_clntcred
  1635. Xfield is either
  1636. X.LW NULL
  1637. Xor points to a well formed structure
  1638. Xthat corresponds to a supported style of authentication credentials.
  1639. XRemember that only
  1640. X.I unix
  1641. Xstyle is currently supported, so (currently)
  1642. X.LW rq_clntcred
  1643. Xcould be cast to a pointer to an
  1644. X.LW authunix_parms
  1645. Xstructure.  If
  1646. X.LW rq_clntcred
  1647. Xis
  1648. X.LW NULL ,
  1649. Xthe service implementor may wish to inspect the other (opaque) fileds of
  1650. X.LW rq_cred
  1651. Xin case the service knows about a new type of authentication
  1652. Xthat the RPC package does not know about.
  1653. X.LP
  1654. XOur remote users service example can be extended so that
  1655. Xit computes results for all users except UID 16:
  1656. X.BS
  1657. X.LS no
  1658. Xnuser(rqstp, tranp)
  1659. X    struct svc_req *rqstp;
  1660. X    SVCXPRT *transp;
  1661. X{
  1662. X    struct authunix_parms *unix_cred;
  1663. X    int uid;
  1664. X    unsigned long nusers;
  1665. X.sp.5
  1666. X    /*
  1667. X     * we don't care about authentication for null proc
  1668. X     */
  1669. X    if (rqstp->rq_proc == NULLPROC) {
  1670. X        if (!svc_sendreply(transp, xdr_void, 0)) {
  1671. X            fprintf(stderr, "can't reply to RPC call\en");
  1672. X            exit(1);
  1673. X         }
  1674. X         return;
  1675. X    }
  1676. X    /*
  1677. X     * now get the uid
  1678. X     */
  1679. X    switch (rqstp->rq_cred.oa_flavor) {
  1680. X    case AUTH_UNIX:
  1681. X        unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
  1682. X        uid = unix_cred->aup_uid;
  1683. X        break;
  1684. X    case AUTH_NULL:
  1685. X    default:
  1686. X        svcerr_weakauth(transp);
  1687. X        return;
  1688. X    }
  1689. X    switch (rqstp->rq_proc) {
  1690. X    case RUSERSPROC_NUM:
  1691. X        /*
  1692. X         * make sure caller is allowed to call this proc
  1693. X         */
  1694. X        if (uid == 16) {
  1695. X            svcerr_systemerr(transp);
  1696. X            return;
  1697. X        }
  1698. X        /*
  1699. X         * code here to compute the number of users
  1700. X         * and put in variable nusers
  1701. X         */
  1702. X        if (!svc_sendreply(transp, xdr_u_long, &nusers) {
  1703. X            fprintf(stderr, "can't reply to RPC call\en");
  1704. X            exit(1);
  1705. X        }
  1706. X        return;
  1707. X    default:
  1708. X        svcerr_noproc(transp);
  1709. X        return;
  1710. X    }
  1711. X}
  1712. X.Lf
  1713. X.BE
  1714. XA few things should be noted here.
  1715. XFirst, it is customary not to check
  1716. Xthe authentication parameters associated with the
  1717. X.LW NULLPROC
  1718. X(procedure number zero).
  1719. XSecond, if the authentication parameter's type is not suitable
  1720. Xfor your service, you should call
  1721. X.LW svcerr_weakauth() .
  1722. XAnd finally, the service protocol itself should return status
  1723. Xfor access denied; in the case of our example, the protocol
  1724. Xdoes not have such a status, so we call the service primitive
  1725. X.LW svcerr_systemerr()
  1726. Xinstead.
  1727. X.LP
  1728. XThe last point underscores the relation between
  1729. Xthe RPC authentication package and the services;
  1730. XRPC deals only with authentication and not with
  1731. Xindividual services' access control.
  1732. XThe services themselves must implement their own access control policies
  1733. Xand reflect these policies as return statuses in their protocols.
  1734. X.NH 2
  1735. XUsing Inetd
  1736. X.LP
  1737. XAn RPC server can be started from
  1738. X.LW inetd .
  1739. XThe only difference
  1740. Xfrom the usual code is that
  1741. X.LW svcudp_create()
  1742. Xshould be called as
  1743. X.BS
  1744. X.LS
  1745. Xtransp = svcudp_create(0);
  1746. X.Lf
  1747. X.BE
  1748. Xsince
  1749. X.LW inet
  1750. Xpasses a socket as file descriptor 0.
  1751. XAlso,
  1752. X.LW svc_register()
  1753. Xshould be called as
  1754. X.BS
  1755. X.LS
  1756. Xsvc_register(transp, PROGNUM, VERSNUM, service, 0);
  1757. X.Lf
  1758. X.BE
  1759. Xwith the final flag as 0,
  1760. Xsince the program would already be registered by
  1761. X.LW inetd .
  1762. XRemember that if you want to exit
  1763. Xfrom the server process and return control to
  1764. X.LW inet ,
  1765. Xyou need to explicitly exit, since
  1766. X.LW svc_run()
  1767. Xnever returns.
  1768. X.LP
  1769. XThe format of entries in /etc/servers for RPC services is
  1770. X.BS
  1771. X.LS
  1772. Xrpc udp \fIserver \0program \0version\fP
  1773. X.Lf
  1774. X.BE
  1775. Xwhere
  1776. X.I server
  1777. Xis the C code implementing the server,
  1778. Xand
  1779. X.I program
  1780. Xand
  1781. X.I version
  1782. Xare the program and version numbers of the service.
  1783. XThe key word
  1784. X.LW udp
  1785. Xcan be replaced by
  1786. X.LW tcp
  1787. Xfor TCP-based RPC services.
  1788. X.LP
  1789. XIf the same program handles multiple versions,
  1790. Xthen the version number can be a range,
  1791. Xas in this example:
  1792. X.BS
  1793. X.LS
  1794. Xrpc udp /usr/etc/rstatd 100001 1-2
  1795. X.Lf
  1796. X.BE
  1797. X.bp
  1798. X.NH
  1799. XMore Examples
  1800. X.NH 2
  1801. XVersions
  1802. X.LP
  1803. XBy convention, the first version number of program
  1804. X.LW PROG
  1805. Xis
  1806. X.LW PROGVERS_ORIG
  1807. Xand the most recent version is
  1808. X.LW PROGVERS .
  1809. XSuppose there is a new version of the
  1810. X.LW user
  1811. Xprogram that returns an
  1812. X.LW "unsigned short"
  1813. Xrather than a
  1814. X.LW long .
  1815. XIf we name this version
  1816. X.LW RUSERSVERS_SHORT ,
  1817. Xthen a server that wants to support both versions
  1818. Xwould do a double register.
  1819. X.BS
  1820. X.LS
  1821. Xif (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,
  1822. X  nuser, IPPROTO_TCP)) {
  1823. X    fprintf(stderr, "can't register RUSER service\en");
  1824. X    exit(1);
  1825. X}
  1826. Xif (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT,
  1827. X  nuser, IPPROTO_TCP)) {
  1828. X    fprintf(stderr, "can't register RUSER service\en");
  1829. X    exit(1);
  1830. X}
  1831. X.Lf
  1832. X.BE
  1833. XBoth versions can be handled by the same C procedure:
  1834. X.BS
  1835. X.LS no
  1836. Xnuser(rqstp, tranp)
  1837. X    struct svc_req *rqstp;
  1838. X    SVCXPRT *transp;
  1839. X{
  1840. X    unsigned long nusers;
  1841. X    unsigned short nusers2
  1842. X.sp.5
  1843. X    switch (rqstp->rq_proc) {
  1844. X    case NULLPROC:
  1845. X        if (!svc_sendreply(transp, xdr_void, 0)) {
  1846. X            fprintf(stderr, "can't reply to RPC call\en");
  1847. X            exit(1);
  1848. X        }
  1849. X        return;
  1850. X    case RUSERSPROC_NUM:
  1851. X        /*
  1852. X         * code here to compute the number of users
  1853. X         * and put in variable nusers
  1854. X         */
  1855. X        nusers2 = nusers;
  1856. X        if (rqstp->rq_vers != RUSERSVERS_ORIG)
  1857. X            return;
  1858. X        if (!svc_sendreply(transp, xdr_u_long, &nusers) {
  1859. X            fprintf(stderr, "can't reply to RPC call\en");
  1860. X            exit(1);
  1861. X        } else
  1862. X        if (!svc_sendreply(transp, xdr_u_short, &nusers2) {
  1863. X            fprintf(stderr, "can't reply to RPC call\en");
  1864. X            exit(1);
  1865. X        }
  1866. X        return;
  1867. X    default:
  1868. X        svcerr_noproc(transp);
  1869. X        return;
  1870. X    }
  1871. X}
  1872. X.Lf
  1873. X.BE
  1874. X.NH 2
  1875. XTCP
  1876. X.LP
  1877. XHere is an example that is essentially
  1878. X.LW rcp .
  1879. XThe initiator of the RPC
  1880. X.LW snd()
  1881. Xcall takes its standard input and sends it to the server
  1882. X.LW rcv() ,
  1883. Xwhich prints it on standard output.
  1884. XThe RPC call uses TCP.
  1885. XThis also illustrates an XDR procedure that behaves differently
  1886. Xon serialization than on deserialization.
  1887. X.BS
  1888. X.LS no
  1889. X/*
  1890. X * The xdr routine:
  1891. X *        on decode, read from wire, write onto fp
  1892. X *        on encode, read from fp, write onto wire
  1893. X */
  1894. X#include <stdio.h>
  1895. X#include <rpc/rpc.h>
  1896. X.sp.5
  1897. Xxdr_rcp(xdrs, fp)
  1898. X    XDR *xdrs;
  1899. X    FILE *fp;
  1900. X{
  1901. X    unsigned long size;
  1902. X    char buf[BUFSIZ], *p;
  1903. X.sp.5
  1904. X    if (xdrs->x_op == XDR_FREE)/* nothing to free */
  1905. X        return 1;
  1906. X    while (1) {
  1907. X        if (xdrs->x_op == XDR_ENCODE) {
  1908. X            if ((size = fread(buf, sizeof(char), BUFSIZ,
  1909. X              fp)) == 0 && ferror(fp)) {
  1910. X                fprintf(stderr, "can't fread\en");
  1911. X                exit(1);
  1912. X            }
  1913. X        }
  1914. X        p = buf;
  1915. X        if (!xdr_bytes(xdrs, &p, &size, BUFSIZ))
  1916. X            return 0;
  1917. X        if (size == 0)
  1918. X            return 1;
  1919. X        if (xdrs->x_op == XDR_DECODE) {
  1920. X            if (fwrite(buf, sizeof(char), size,
  1921. X              fp) != size) {
  1922. X                fprintf(stderr, "can't fwrite\en");
  1923. X                exit(1);
  1924. X            }
  1925. X        }
  1926. X    }
  1927. X}
  1928. X.sp.5
  1929. X/*
  1930. X * The sender routines
  1931. X */
  1932. X#include <stdio.h>
  1933. X#include <netdb.h>
  1934. X#include <rpc/rpc.h>
  1935. X#include <sys/socket.h>
  1936. X#include <sys/time.h>
  1937. X.sp.5
  1938. Xmain(argc, argv)
  1939. X    int argc;
  1940. X    char **argv;
  1941. X{
  1942. X    int err;
  1943. X.sp.5
  1944. X    if (argc < 2) {
  1945. X        fprintf(stderr, "usage: %s servername\en", argv[0]);
  1946. X        exit(-1);
  1947. X    }
  1948. X    if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC_FP,
  1949. X      RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {
  1950. X        clnt_perrno(err);
  1951. X        fprintf(stderr, "can't make RPC call\en");
  1952. X        exit(1);
  1953. X    }
  1954. X}
  1955. X.sp.5
  1956. Xcallrpctcp(host, prognum, procnum, versnum,
  1957. X           inproc, in, outproc, out)
  1958. X    char *host, *in, *out;
  1959. X    xdrproc_t inproc, outproc;
  1960. X{
  1961. X    struct sockaddr_in server_addr;
  1962. X    int socket = RPC_ANYSOCK;
  1963. X    enum clnt_stat clnt_stat;
  1964. X    struct hostent *hp;
  1965. X    register CLIENT *client;
  1966. X    struct timeval total_timeout;
  1967. X.sp.5
  1968. X    if ((hp = gethostbyname(host)) == NULL) {
  1969. X        fprintf(stderr, "can't get addr for '%s'\en", host);
  1970. X        exit(-1);
  1971. X    }
  1972. X    bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
  1973. X        hp->h_length);
  1974. X    server_addr.sin_family = AF_INET;
  1975. X    server_addr.sin_port =  0;
  1976. X    if ((client = clnttcp_create(&server_addr, prognum,
  1977. X      versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
  1978. X        perror("rpctcp_create");
  1979. X        exit(-1);
  1980. X    }
  1981. X    total_timeout.tv_sec = 20;
  1982. X    total_timeout.tv_usec = 0;
  1983. X    clnt_stat = clnt_call(client, procnum,
  1984. X        inproc, in, outproc, out, total_timeout);
  1985. X    clnt_destroy(client)
  1986. X    return (int)clnt_stat;
  1987. X}
  1988. X.sp.5
  1989. X/*
  1990. X * The receiving routines
  1991. X */
  1992. X#include <stdio.h>
  1993. X#include <rpc/rpc.h>
  1994. X.sp.5
  1995. Xmain()
  1996. X{
  1997. X    register SVCXPRT *transp;
  1998. X.sp.5
  1999. X    if ((transp = svctcp_create(RPC_ANYSOCK,
  2000. X      BUFSIZ, BUFSIZ)) == NULL) {
  2001. X        fprintf("svctcp_create: error\en");
  2002. X        exit(1);
  2003. X    }
  2004. X    pmap_unset(RCPPROG, RCPVERS);
  2005. X    if (!svc_register(transp,
  2006. X      RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
  2007. X        fprintf(stderr, "svc_register: error\en");
  2008. X        exit(1);
  2009. X    }
  2010. X    svc_run();  /* never returns */
  2011. X    fprintf(stderr, "svc_run should never return\en");
  2012. X}
  2013. X.sp.5
  2014. Xrcp_service(rqstp, transp)
  2015. X    register struct svc_req *rqstp;
  2016. X    register SVCXPRT *transp;
  2017. X{
  2018. X    switch (rqstp->rq_proc) {
  2019. X    case NULLPROC:
  2020. X        if (svc_sendreply(transp, xdr_void, 0) == 0) {
  2021. X            fprintf(stderr, "err: rcp_service");
  2022. X            exit(1);
  2023. X        }
  2024. X        return;
  2025. X    case RCPPROC_FP:
  2026. X        if (!svc_getargs(transp, xdr_rcp, stdout)) {
  2027. X            svcerr_decode(transp);
  2028. X            return;
  2029. X        }
  2030. X        if (!svc_sendreply(transp, xdr_void, 0)) {
  2031. X            fprintf(stderr, "can't reply\en");
  2032. X            return;
  2033. X        }
  2034. X        exit(0);
  2035. X    default:
  2036. X        svcerr_noproc(transp);
  2037. X        return;
  2038. X    }
  2039. X}
  2040. X.Lf
  2041. X.BE
  2042. X.NH 2
  2043. XCallback Procedures
  2044. X.LP
  2045. XOccasionally, it is useful to have a server become a client,
  2046. Xand make an RPC call back the process which is its client.
  2047. XAn example is remote debugging,
  2048. Xwhere the client is a window system program,
  2049. Xand the server is a debugger running on the remote machine.
  2050. XMost of the time,
  2051. Xthe user clicks a mouse button at the debugging window,
  2052. Xwhich converts this to a debugger command,
  2053. Xand then makes an RPC call to the server
  2054. X(where the debugger is actually running),
  2055. Xtelling it to execute that command.
  2056. XHowever, when the debugger hits a breakpoint, the roles are reversed,
  2057. Xand the debugger wants to make an rpc call to the window program,
  2058. Xso that it can inform the user that a breakpoint has been reached.
  2059. SHAR_EOF
  2060. if test 49365 -ne "`wc -c < 'rpc/doc/rpc.prog.p1'`"
  2061. then
  2062.     echo shar: "error transmitting 'rpc/doc/rpc.prog.p1'" '(should have been 49365 characters)'
  2063. fi
  2064. chmod 444 'rpc/doc/rpc.prog.p1'
  2065. fi
  2066. exit 0
  2067. #    End of shell archive
  2068.  
  2069.